home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
gofer221.zip
/
OUTPUT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
16KB
|
632 lines
/* --------------------------------------------------------------------------
* output.c: Copyright (c) Mark P Jones 1991. All rights reserved.
* See goferite.h for details and conditions of use etc...
* Gofer version 2.21 November 1991
*
* Last updated 03/11/91 mpj
*
* Unparse expressions and types - for use in error messages, type checker
* and for debugging.
* ------------------------------------------------------------------------*/
#include "prelude.h"
#include "storage.h"
#include "connect.h"
#include "errors.h"
#include <ctype.h>
/* --------------------------------------------------------------------------
* Local function prototypes:
* ------------------------------------------------------------------------*/
static Void local put Args((Int,Cell));
static Void local putQual Args((Cell));
static Bool local isDictVal Args((Cell));
static Cell local maySkipDict Args((Cell));
static Void local putAp Args((Int,Cell));
static Void local putOverInfix Args((Int,Text,Syntax,Cell));
static Void local putInfix Args((Int,Text,Syntax,Cell,Cell));
static Void local putSimpleAp Args((Cell));
static Void local putTuple Args((Int,Cell));
static Int local unusedTups Args((Int,Cell));
static Void local unlexVar Args((Text));
static Void local unlexOp Args((Text));
static Void local unlexCharConst Args((Cell));
static Void local unlexStrConst Args((Text));
static Void local putSigType Args((Cell));
static Void local putContext Args((List));
static Void local putPred Args((Cell));
static Void local putType Args((Cell,Int));
static Bool local putTupleType Args((Cell));
static Void local putConType Args((Cell));
/* --------------------------------------------------------------------------
* Basic output routines:
* ------------------------------------------------------------------------*/
static FILE *outputStream;
Bool showDicts = TRUE; /* TRUE => include dictionary vars */
/* in output expressions */
#define OPEN(b) if (b) putChr('(');
#define CLOSE(b) if (b) putChr(')');
#define putChr(c) fputc(c,outputStream)
#define putInt(n) fprintf(outputStream,"%d",n)
#define putStr(m) fprintf(outputStream,"%s",m)
/* --------------------------------------------------------------------------
* Precedence values (See Haskell report p.10):
* ------------------------------------------------------------------------*/
#define ALWAYS FUN_PREC /* Always use parens (unless atomic)*/
/* User defined operators have prec */
/* in the range MIN_PREC..MAX_PREC */
#define ARROW_PREC MAX_PREC /* for printing -> in type exprs */
#define COCO_PREC (MIN_PREC-1) /* :: is left assoc, low precedence */
#define COND_PREC (MIN_PREC-2) /* conditional expressions */
#define WHERE_PREC (MIN_PREC-3) /* where expressions */
#define LAM_PREC (MIN_PREC-4) /* lambda abstraction */
#define NEVER LAM_PREC /* Never use parentheses */
/* --------------------------------------------------------------------------
* Print an expression (used to display context of type errors):
* ------------------------------------------------------------------------*/
static Void local put(d,e) /* print expression e in context of */
Int d; /* operator of precedence d */
Cell e; {
List xs;
switch (whatIs(e)) {
case FINLIST : putChr('[');
xs = snd(e);
if (nonNull(xs)) {
put(NEVER,hd(xs));
while (nonNull(xs=tl(xs))) {
putChr(',');
put(NEVER,hd(xs));
}
}
putChr(']');
break;
case AP : putAp(d,e);
break;
case NAME : unlexVar(name(e).text);
break;
case VARIDCELL :
case VAROPCELL :
case DICTVAR :
case CONIDCELL :
case CONOPCELL : unlexVar(textOf(e));
break;
case DICTCELL : putStr("{dict}");
break;
case SELECT : putStr("#");
putInt(selectOf(e));
break;
case UNIT : putStr("()");
break;
case TUPLE : putTuple(tupleOf(e),e);
break;
case WILDCARD : putChr('_');
break;
case ASPAT : put(NEVER,fst(snd(e)));
putChr('@');
put(ALWAYS,snd(snd(e)));
break;
case LAZYPAT : putChr('~');
put(ALWAYS,snd(e));
break;
case LISTCOMP : putStr("[ ");
put(NEVER,fst(snd(e)));
putStr(" | ");
xs = snd(snd(e));
if (nonNull(xs)) {
putQual(hd(xs));
while (nonNull(xs=tl(xs))) {
putStr(", ");
putQual(hd(xs));
}
}
putChr(']');
break;
case CHARCELL : unlexCharConst(charOf(e));
break;
case INTCELL : putInt(intOf(e));
break;
case FLOATCELL : putStr(floatToString(floatOf(e)));
break;
case STRCELL : unlexStrConst(textOf(e));
break;
case LETREC : OPEN(d>WHERE_PREC);
#ifdef DEBUG_CODE
putStr("let {");
put(NEVER,fst(snd(e)));
putStr("} in ");
#else
putStr("let {...} in ");
#endif
put(WHERE_PREC+1,snd(snd(e)));
CLOSE(d>WHERE_PREC);
break;
case COND : OPEN(d>COND_PREC);
putStr("if ");
put(COND_PREC+1,fst3(snd(e)));
putStr(" then ");
put(COND_PREC+1,snd3(snd(e)));
putStr(" else ");
put(COND_PREC+1,thd3(snd(e)));
CLOSE(d>COND_PREC);
break;
case LAMBDA : xs = fst(snd(e));
if (!showDicts) {
while (nonNull(xs) && isDictVal(hd(xs)))
xs = tl(xs);
if (isNull(xs)) {
put(d,snd(snd(snd(e))));
break;
}
}
OPEN(d>LAM_PREC);
putChr('\\');
if (nonNull(xs)) {
put(ALWAYS,hd(xs));
while (nonNull(xs=tl(xs))) {
putChr(' ');
put(ALWAYS,hd(xs));
}
}
putStr(" -> ");
put(LAM_PREC,snd(snd(snd(e))));
CLOSE(d>LAM_PREC);
break;
case ESIGN : OPEN(d>COCO_PREC);
put(COCO_PREC,fst(snd(e)));
putStr(" :: ");
putSigType(snd(snd(e)));
CLOSE(d>COCO_PREC);
break;
case CASE : putStr("case ");
put(NEVER,fst(snd(e)));
#ifdef DEBUG_CODE
putStr(" of {");
put(NEVER,snd(snd(e)));
putChr('}');
#else
putStr(" of {...}");
#endif
break;
case INDIRECT : putChr('^');
put(ALWAYS,snd(e));
break;
default : /*internal("put");*/
putChr('$');
putInt(e);
break;
}
}
static Void local putQual(q) /* print list comp qualifier */
Cell q; {
switch (whatIs(q)) {
case BOOLQUAL : put(NEVER,snd(q));
return;
case QWHERE : put(ALWAYS,fst(snd(q)));
putChr('=');
put(NEVER,snd(snd(q)));
return;
case FROMQUAL : put(ALWAYS,fst(snd(q)));
putStr("<-");
put(NEVER,snd(snd(q)));
return;
}
}
static Bool local isDictVal(e) /* Look for dictionary value */
Cell e; {
switch (whatIs(e)) {
case AP : return isSelect(fun(e));
case DICTCELL :
case DICTVAR : return TRUE;
}
return FALSE;
}
static Cell local maySkipDict(e) /* descend function application */
Cell e; { /* possibly ignoring dict aps */
if (!showDicts)
while (isAp(e) && isDictVal(arg(e)))
e = fun(e);
return e;
}
static Void local putAp(d,e) /* print application (args>=1) */
Int d;
Cell e; {
Bool anyDictArgs = FALSE;
Cell h;
Text t;
Syntax sy;
Int args = 0;
for (h=e; isAp(h); h=fun(h)) /* find head of expression, looking*/
if (isDictVal(arg(h))) { /* for dictionary arguments */
anyDictArgs = TRUE;
if (showDicts)
args++;
}
else
args++;
if (args==0) { /* Special case when *all* args */
put(d,h); /* are dictionary values */
return;
}
switch (whatIs(h)) {
case ADDPAT : if (args==1)
putInfix(d,textPlus,syntaxOf(textPlus),
arg(e),mkInt(intValOf(fun(e))));
else
putStr("ADDPAT");
return;
case MULPAT : if (args==1)
putInfix(d,textMult,syntaxOf(textMult),
mkInt(intValOf(fun(e))),arg(e));
else
putStr("MULPAT");
return;
case TUPLE : OPEN(args>tupleOf(h) && d>=FUN_PREC);
putTuple(tupleOf(h),e);
CLOSE(args>tupleOf(h) && d>=FUN_PREC);
return;
case NAME : sy = syntaxOf(t = name(h).text);
break;
case VARIDCELL :
case VAROPCELL :
case DICTVAR :
case CONIDCELL :
case CONOPCELL : sy = syntaxOf(t = textOf(h));
break;
default : sy = APPLIC;
break;
}
e = maySkipDict(e);
if (showDicts && anyDictArgs) /* expressions involving dicts */
sy = APPLIC; /* are printed applicatively */
if (sy==APPLIC) { /* print simple application */
OPEN(d>=FUN_PREC);
putSimpleAp(e);
CLOSE(d>=FUN_PREC);
return;
}
else if (args==1) { /* print section of the form (e+) */
putChr('(');
put(FUN_PREC-1,arg(e));
putChr(' ');
unlexOp(t);
putChr(')');
}
else if (args==2) /* infix expr of the form e1 + e2 */
putInfix(d,t,sy,arg(maySkipDict(fun(e))),arg(e));
else { /* o/w (e1 + e2) e3 ... en (n>=3) */
OPEN(d>=FUN_PREC);
putOverInfix(args,t,sy,e);
CLOSE(d>=FUN_PREC);
}
}
static Void local putOverInfix(args,t,sy,e)
Int args; /* infix applied to >= 3 arguments */
Text t;
Syntax sy;
Cell e; {
if (args>2) {
putOverInfix(args-1,t,sy,maySkipDict(fun(e)));
putChr(' ');
put(FUN_PREC,arg(e));
}
else
putInfix(ALWAYS,t,sy,arg(maySkipDict(fun(e))),arg(e));
}
static Void local putInfix(d,t,sy,e,f) /* print infix expression */
Int d;
Text t; /* Infix operator symbol */
Syntax sy; /* with name t, syntax s */
Cell e, f; { /* Left and right operands */
Syntax a = assocOf(sy);
Int p = precOf(sy);
OPEN(d>p);
put((a==LEFT_ASS ? p : 1+p), e);
putChr(' ');
unlexOp(t);
putChr(' ');
put((a==RIGHT_ASS ? p : 1+p), f);
CLOSE(d>p);
}
static Void local putSimpleAp(e) /* print application e0 e1 ... en */
Cell e; {
if (isAp(e)) {
putSimpleAp(maySkipDict(fun(e)));
putChr(' ');
put(FUN_PREC,arg(e));
}
else
put(FUN_PREC,e);
}
static Void local putTuple(ts,e) /* Print tuple expression, allowing*/
Int ts; /* for possibility of either too */
Cell e; { /* few or too many args to constr */
Int i;
putChr('(');
if ((i=unusedTups(ts,e))>0) {
while (--i>0)
putChr(',');
putChr(')');
}
}
static Int local unusedTups(ts,e) /* print first part of tuple expr */
Int ts; /* returning number of constructor */
Cell e; { /* args not yet printed ... */
if (isAp(e)) {
if ((ts=unusedTups(ts,fun(e))-1)>=0) {
put(NEVER,arg(e));
putChr(ts>0?',':')');
}
else {
putChr(' ');
put(FUN_PREC,arg(e));
}
}
return ts;
}
static Void local unlexVar(t) /* print text as a variable name */
Text t; { /* operator symbols must be enclosed*/
String s = textToStr(t); /* in parentheses... except [] ... */
if ((isascii(s[0]) && isalpha(s[0])) || s[0]=='_' || strcmp(s,"[]")==0)
putStr(s);
else {
putChr('(');
putStr(s);
putChr(')');
}
}
static Void local unlexOp(t) /* print text as operator name */
Text t; { /* alpha numeric symbols must be */
String s = textToStr(t); /* enclosed by backquotes */
if (isascii(s[0]) && isalpha(s[0])) {
putChr('`');
putStr(s);
putChr('`');
}
else
putStr(s);
}
static Void local unlexCharConst(c)
Cell c; {
putChr('\'');
putStr(unlexChar(c,'\''));
putChr('\'');
}
static Void local unlexStrConst(t)
Text t; {
String s = textToStr(t);
static Char SO = 14; /* ASCII code for '\SO' */
Bool lastWasSO = FALSE;
Bool lastWasDigit = FALSE;
Bool lastWasEsc = FALSE;
putChr('\"');
for (; *s; s++) {
String ch = unlexChar(*s,'\"');
Char c = ' ';
if ((lastWasSO && *ch=='H') ||
(lastWasEsc && lastWasDigit && isascii(*ch) && isdigit(*ch)))
putStr("\\&");
lastWasEsc = (*ch=='\\');
lastWasSO = (*s==SO);
for (; *ch; c = *ch++)
putChr(*ch);
lastWasDigit = (isascii(c) && isdigit(c));
}
putChr('\"');
}
/* --------------------------------------------------------------------------
* Print type expression:
* ------------------------------------------------------------------------*/
static Void local putSigType(t) /* print (possibly) generic type */
Cell t; {
if (isPolyType(t)) /* skip (forall _) part (if any) */
t = snd(t);
if (whatIs(t)==QUAL) { /* Handle qualified types */
putContext(fst(snd(t)));
putStr(" => ");
t = snd(snd(t));
}
putType(t,NEVER); /* Finally, print rest of type ... */
}
static Void local putContext(qs) /* print context list */
List qs; {
if (isNull(qs))
putStr("()");
else {
Int nq = length(qs);
if (nq!=1) putChr('(');
putPred(hd(qs));
while (nonNull(qs=tl(qs))) {
putStr(", ");
putPred(hd(qs));
}
if (nq!=1) putChr(')');
}
}
static Void local putPred(pi) /* Output predicate */
Cell pi; {
if (isAp(pi)) {
putPred(fun(pi));
putChr(' ');
putType(arg(pi),ALWAYS);
}
else if (isClass(pi))
putStr(textToStr(class(pi).text));
else if (isCon(pi))
putStr(textToStr(textOf(pi)));
else
putStr("<unknownPredicate>");
}
static Void local putType(t,prec) /* print nongeneric type expression*/
Cell t;
Int prec; {
Cell typeHead=getHead(t);
switch(whatIs(typeHead)) {
case UNIT : putStr("()");
return;
case TUPLE : putChr('(');
putTupleType(t);
putChr(')');
break;
case LIST : putChr('[');
putType(arg(t),NEVER);
putChr(']');
break;
case OFFSET: putChr('a'+offsetOf(typeHead));
break;
case INTCELL : putChr('_');
putInt(intOf(t));
break;
case TYCON : { Bool brackets = (argCount!=0 && prec>=ALWAYS);
OPEN(brackets);
putConType(t);
CLOSE(brackets);
}
break;
case ARROW : OPEN(prec>=ARROW_PREC);
putType(arg(fun(t)),ARROW_PREC);
putStr(" -> ");
putType(arg(t),NEVER);
CLOSE(prec>=ARROW_PREC);
break;
default : putStr("(bad type)");
}
}
static Bool local putTupleType(e) /* print tuple of types, returning */
Cell e; { /* TRUE if something was printed, */
if (isAp(e)) { /* FALSE otherwise; used to control*/
if (putTupleType(fun(e))) /* printing of intermed. commas */
putChr(',');
putType(arg(e),NEVER);
return TRUE;
}
return FALSE;
}
static Void local putConType(t) /* print type of form Tycon t1...tn*/
Cell t; {
if (isAp(t)) {
putConType(fun(t));
putChr(' ');
putType(arg(t),ALWAYS);
}
else if (isTycon(t))
putStr(textToStr(tycon(t).text));
else
putStr("(bad type)");
}
/* --------------------------------------------------------------------------
* Main drivers:
* ------------------------------------------------------------------------*/
Void printExp(fp,e) /* print expr on specified stream */
FILE *fp;
Cell e; {
outputStream = fp;
put(NEVER,e);
}
Void printType(fp,t) /* print type on specified stream */
FILE *fp;
Cell t; {
outputStream = fp;
putSigType(t);
}
Void printContext(fp,qs) /* print context on spec. stream */
FILE *fp;
List qs; {
outputStream = fp;
putContext(qs);
}
Void printPred(fp,pi) /* print predicate pi on stream */
FILE *fp;
Cell pi; {
outputStream = fp;
putPred(pi);
}
/*-------------------------------------------------------------------------*/